/*
*
*
*     文档创建：jjl, jjl@hzncc.com
*/


module packet_trans(
            sys_clk         ,
            sys_reset_n     ,

            //报文处理端信号
            rxdv            ,
            rxd             ,
            txen            ,
            txd
        );

    input           sys_clk         ;
    input           sys_reset_n     ;

    //报文处理接口
    input           rxdv            ;
    input   [1:0]   rxd             ;
    output          txen            ;
    output  [1:0]   txd             ;

    //接收数据状态机
    typedef enum logic [2:0] {RCV_IDLE, RCV_PRE, RCV_DMAC, RCV_SMAC, RCV_TYPE, RCV_DATA} rcv_status_t;
    rcv_status_t rcv_status_curr;
    rcv_status_t rcv_status_next;
    always_ff@(posedge sys_clk or negedge sys_reset_n) //状态转移段
    if(~sys_reset_n)    begin
        rcv_status_curr     <=      RCV_IDLE    ;
    end else begin
        rcv_status_curr     <=      rcv_status_next     ;
    end

    //以太网帧头计数器
    //标识出，目的MAC，源MAC，帧类型，共14字节，56个clk，所以最小计数为64
    logic [5:0] eth_hdr_cnt_r       ;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n) 
        eth_hdr_cnt_r       <=      '0    ;
    else if((rcv_status_curr == RCV_DMAC) | (rcv_status_curr == RCV_SMAC) | (rcv_status_curr == RCV_TYPE))
        eth_hdr_cnt_r       <=      eth_hdr_cnt_r + 1'b1    ;
    else 
        eth_hdr_cnt_r       <=      '0    ;

    always_comb begin //状态转移条件判断
        rcv_status_next = RCV_IDLE;
        case(rcv_status_curr)
            RCV_IDLE:  //IDLE状态下，等待rxdv拉高     
                if(rxdv)  
                    rcv_status_next = RCV_PRE; 
                else 
                    rcv_status_next = RCV_IDLE;
            RCV_PRE:    //前导符状态下，等待定界符
                if(rxdv & (rxd==2'b11)) 
                    rcv_status_next = RCV_DMAC; 
                else if(rxdv)
                    rcv_status_next = RCV_PRE;
                else
                   rcv_status_next = RCV_IDLE; 
            RCV_DMAC:   //接收目的MAC地址
                if(rxdv & (eth_hdr_cnt_r < 6'd24))
                    rcv_status_next = RCV_DMAC;
                else if(rxdv)
                    rcv_status_next = RCV_SMAC;
                else
                   rcv_status_next = RCV_IDLE; 
            RCV_SMAC:   //接收源MAC地址
                if(eth_hdr_cnt_r < 6'd48)
                    rcv_status_next = RCV_SMAC;
                else if(rxdv)
                    rcv_status_next = RCV_TYPE;
                else
                   rcv_status_next = RCV_IDLE; 
            RCV_TYPE:  //接收帧类型
                if(eth_hdr_cnt_r < 6'd54)
                    rcv_status_next = RCV_TYPE;
                else if(rxdv)
                    rcv_status_next = RCV_DATA;
                else
                   rcv_status_next = RCV_IDLE; 
            RCV_DATA:   //接受数据
                if(rxdv)
                    rcv_status_next = RCV_DATA;
                else
                    rcv_status_next = RCV_IDLE;
            default:
                   rcv_status_next = RCV_IDLE;          
        endcase
    end

    //当在RCV_DMAC时候，开始写数据，写信号和写地址生成
    logic               rcv_wr              ;
    logic   [12:0]      rcv_wr_addr         ;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n)    begin
        rcv_wr      <=  '0;
        rcv_wr_addr <=  '0;
    end else if((rcv_status_curr == RCV_DMAC) | (rcv_status_curr == RCV_SMAC) | (rcv_status_curr == RCV_TYPE) | (rcv_status_curr == RCV_DATA))begin
        rcv_wr      <=  1'b1;   //写信号有效
        rcv_wr_addr <=  rcv_wr_addr + 1'b1;
    end else if((rcv_status_curr == RCV_PRE) & (rcv_status_next == RCV_DMAC)) begin //帧定界符时刻对地址清零，确保数据发送完毕
        rcv_wr_addr <=  '0;
    end else
        rcv_wr      <=  '0;

    //例化双口ram
    wire    [1:0]       tx_data     ;
    dpram_13_2  u_trans_ram (
        //a端口只写
        .clk_a          (           sys_clk         ),
        .addr_a         (           rcv_wr_addr     ),
        .data_a         (           rxd             ),
        .we_a           (           rcv_wr          ),
        .q_a            (                           ),
        //b端口只读
        .clk_b          (           sys_clk         ),
        .addr_b         (           snd_addr        ),
        .data_b         (           2'b00           ),
        .we_b           (           1'b0            ),
        .q_b            (           tx_data         )
    );

    //数据发送端
    //在DMAC状态下开始发送
    logic   [12:0]      snd_addr            ;
    logic               snd_enable          ;
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n) 
        snd_enable  <=  '0;
    else if (rcv_status_next == RCV_DMAC)    //此状态下开始发送
        snd_enable  <=  1'b1;
    else if (snd_addr == rcv_wr_addr)    //数据发送完毕后结束
        snd_enable  <=  1'b0;

    assign txen = snd_enable    ;
    //首先发送前导符，接着发送定界符，接着读取ram，发送ram中数据
    logic   [5:0]   cnt_pre_r   ;   //前导符计数，至少31个
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n) 
        cnt_pre_r   <=  '0;
    else if(snd_enable & (cnt_pre_r < 6'd32))
        cnt_pre_r   <= cnt_pre_r + 1'b1;
    else if(~snd_enable)
        cnt_pre_r   <=  '0;

    assign txd = (cnt_pre_r < 6'd31) ? 2'b01:
                (cnt_pre_r == 6'd31)? 2'b11:tx_data;

    //发送地址生成
    always_ff@(posedge sys_clk or negedge sys_reset_n)
    if(~sys_reset_n)    begin
        snd_addr    <=  '0;
    end else if(snd_enable & (cnt_pre_r > 6'd31))
        snd_addr    <=  snd_addr + 1'b1;
    else 
        snd_addr    <=  '0;

endmodule
